package com.yh.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yh.config.OtherSource;
import com.yh.dao.UserDao;
import com.yh.entity.User;
import com.yh.service.UserService;
import com.yh.service.redis.UpdateDataToRedis;
import com.yh.utils.*;
import com.yh.vo.CustomPageAndNavigate;
import com.yh.vo.LoginVO;
import com.yh.vo.UserVO;
import io.minio.MinioClient;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yuhuan
 * @date 2022/01/13
 */
@DubboService
public class UserServiceImpl implements UserService {
    /**
     * 日志
     */
    private static final Logger logger = Logger.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MinioClient minioClient;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private UpdateDataToRedis redis;
    @Autowired
    private OtherSource otherSource;

    @Override
    public CustomPageAndNavigate<UserVO> findUserAll(Integer pageNum, Integer pageSize) {
        List<User> userList = userDao.findUserAll();
        List<UserVO> users = new ArrayList();
        userList.forEach(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            users.add(userVO);
        });
        return new CustomPageAndNavigate(pageNum, pageSize, users);
    }

    @Override
    public UserVO findUserById(String userId) {
        User user = findUserByIdFromRedis(userId);
        // 缓存没有到数据库找
        if (ObjectUtils.isEmpty(user)) {
            user = userDao.findUserById(userId);
            // 数据库没有，则直接返回
            if (ObjectUtils.isEmpty(user)) {
                return null;
            }
            // 处理头像地址
            user = ImgUrl.userImageHandler(minioClient, otherSource, user);
        }
        UserVO userVo = new UserVO();
        BeanUtils.copyProperties(user, userVo);
        return userVo;
    }

    @Override
    public User findUserByIdFromRedis(String userId) {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        // 拼接登录信息在Redis中的唯一KEY
        String userKey = Constants.LoginData.LOGIN_DATA_PREFIX_KEY + ":" + userId;
        // 从redis中获取用户信息
        Object userJson = valueOperations.get(userKey);
        if (ObjectUtils.isEmpty(userJson)) {
            return null;
        }
        try {
            User user = objectMapper.readValue((String) userJson, User.class);
            return user;
        } catch (JsonProcessingException e) {
            logger.error(">>>>> 用户信息在反序列化时出现问题" + e.getMessage());
        }
        return null;
    }

    @Override
    public UserVO findLoginUserById(String userId) {
        UserVO userVo = null;
        User user = findUserByIdFromRedis(userId);
        if (!ObjectUtils.isEmpty(user)) {
            userVo = new UserVO();
            // 处理用户头像
            user = ImgUrl.userImageHandler(minioClient, otherSource, user);
            user = removeSensitiveData(user);
            BeanUtils.copyProperties(user, userVo);
        }
        return userVo;
    }

    @Override
    public int userRegister(LoginVO vo) {
        if (ObjectUtils.isEmpty(vo)) {
            return Constants.ResponseDataState.EXIST_ACCOUNT;
        }
        User user = voCopyToUser(vo);
        // 检查当前账户是否已经被注册
        boolean exist = isExist(user.getUserAccount());
        if (exist) {
            return Constants.ResponseDataState.EXIST_ACCOUNT;
        }
        // 检查邮箱格式
        int isEmail = DataFormatValidator.validatorEmail(vo.getEmail());
        if (isEmail != Constants.ValidatorResult.DATA_PASS) {
            return isEmail;
        }
        // 生成用户ID
        user.setUserId(RandomAttributeBuilder.createidfromUuid());
        // 生成随机的用户昵称
        user.setUserName(RandomAttributeBuilder.createRandomStr(5));
        // 密码加密处理
        user = encryption(user.getUserPwd(), user);
        userDao.addNewUser(user);
        return Constants.ResponseDataState.RESP_SUCCESS;
    }

    @Override
    public int updateUserData(UserVO userVO) {
        int valResult = DataFormatValidator.userValidator(userVO);
        // 验证数据的格式
        if (valResult != Constants.ValidatorResult.DATA_PASS) {
            // 如果用户昵称为空，便生成随机的昵称
            if (valResult == Constants.ValidatorResult.NULL_VALUE) {
                userVO.setUserName(RandomAttributeBuilder.createRandomStr(5));
            } else {
                return valResult;
            }
        }
        User user = new User();
        BeanUtils.copyProperties(userVO, user);
        // 将数据修改到数据库
        userDao.updateUserData(user);
        // 更新用户的登录信息
        redis.updateLoginUser(userVO.getUserId());
        return Constants.ResponseDataState.RESP_SUCCESS;
    }

    @Override
    public int updatePassWord(UserVO userVO) {
        User oldUserData = userDao.findUserById(userVO.getUserId());
        // 判断用户密码是否正确
        String securityPwd = Md5Security.makePrefixToMd5(oldUserData.getPwdPrefix(), userVO.getUserPwd());
        boolean isCorrect = oldUserData.getSecurityPwd().equals(securityPwd);
        if (!isCorrect) {
            return Constants.ResponseDataState.PASSWORD_ERROR;
        }
        // 修改密码
        oldUserData.setUserPwd(userVO.getNewPassword());
        User newUserData = encryption(userVO.getNewPassword(), oldUserData);
        userDao.updatePassWord(newUserData);
        return Constants.ResponseDataState.RESP_SUCCESS;
    }

    /**
     * 将登录信息拷贝到用户信息
     */
    private User voCopyToUser(LoginVO vo) {
        User user = new User();
        // 拷贝相同字段的信息
        BeanUtils.copyProperties(vo, user);
        // 拷贝不同字段的信息
        user.setUserEmail(vo.getEmail());
        user.setUserPwd(vo.getPassWord());
        return user;
    }

    /**
     * 检查账户是否已经存在
     */
    private boolean isExist(String userAccount) {
        User userByAccount = userDao.findUserByAccount(userAccount);
        return !ObjectUtils.isEmpty(userByAccount);
    }

    /**
     * 剔除用户的敏感信息
     */
    private User removeSensitiveData(User user) {
        user.setUserAccount(null);
        user.setPwdPrefix(null);
        user.setSecurityPwd(null);
        return user;
    }

    /**
     * 给密码设置加密
     */
    private User encryption(String password, User user) {
        String randomString = Md5Security.getRandomString(10);
        user.setPwdPrefix(randomString);
        user.setSecurityPwd(Md5Security.makePrefixToMd5(randomString, password));
        return user;
    }
}
